#!/usr/bin/env python
# _*_ coding:utf-8 _*_

import sys
import socket
import threading
import re
import urllib

http_header_pattern = re.compile(r'[GET|POST|HEAD|PUT|DELETE]\s(\w.*)\sHTTP/1.\d')


def hexdump(src, length=16):
    result = []
    digits = 4 if isinstance(src, unicode) else 2

    for i in xrange(0,len(src),length):
        s = src[i:i+length]
        hexa = b' '.join(["%0*X"%(digits,ord(x)) for x in s])
        text = b''.join(x if 0x20 <= ord(x) < 0x7F else b'.' for x in s)
        result.append(b"%04X    %-*s    %s"%(i,length*(digits +1),hexa,text))
    print b'\n'.join(result)
    return b'\n'.join(result)


def receive_from(connection):
    buffer = ""

    connection.settimeout(2)
    try:
        while True:
            data = connection.recv(4096)
            if not data:
                break

            buffer += data
    except:
        pass

    return buffer


def request_handler(buffer):
    return buffer


def response_handler(buffer):
    return buffer


def parse_http_header(buffer):
    match = http_header_pattern.search(buffer)
    if not match:
        return 0,0
    url_txt = match.group(1)
    if not url_txt.startswith('http://'):
        url_txt = "http://" + url_txt
    print url_txt

    proto, rest = urllib.splittype(url_txt)
    host, rest = urllib.splithost(rest)
    host, port = urllib.splitport(host)
    if port is None:
        port = 80
    return host,port

def is_in_black_list(host):
    if host.find('amap')!=-1:
        return True

    return False

def proxy_handler(client_socket, addr):
    print '-------------------------------------'
    remote_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # remote_socket.connect((remote_host,remote_port))

    print client_socket.getpeername()
    print client_socket.getsockname()


    local_buffer = receive_from(client_socket)
    if not len(local_buffer):
        return


    host,port = parse_http_header(local_buffer)
    if not host or is_in_black_list(host):
        return


    remote_socket.connect((host, port))


    file = open(str(host)+str(addr[1])+".log",'w');
    file.write(local_buffer)
    
    print '[<===] Received %d bytes from localhost' % len(local_buffer)
    hexdump(local_buffer)
    local_buffer = request_handler(local_buffer)
    remote_socket.send(local_buffer)
    print '[===>] send to remote'

    while True:

        remote_buffer = receive_from(remote_socket)

        if len(remote_buffer):
            print '[<===] receive %d bytes from remote' % len(remote_buffer)
            hexdump(remote_buffer)

            remote_buffer = response_handler(remote_buffer)
            file.write(remote_buffer)
            client_socket.send(remote_buffer)
            print '[<=== send to localhost'

        local_buffer = receive_from(client_socket)

        if len(local_buffer):
            print '[===>] Received %d bytes from localhost' % len(local_buffer)
            hexdump(local_buffer)
            local_buffer = request_handler(local_buffer)
            file.write(local_buffer)
            remote_socket.send(local_buffer)
            print '[===>] send to remote'

        if not len(local_buffer) or not len(remote_buffer):
            client_socket.close()
            remote_socket.close()
            file.close()
            print '[*] No more data .Closing connections'
            break


def server_loop(local_port):
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    local_host = '0.0.0.0'
    try:
        server.bind((local_host, local_port))
    except:
        print 'Failed to listen on %s:%d' % (local_host, local_port)
        sys.exit(0)

    print '[*] Listening on %s:%d' % (local_host, local_port)

    server.listen(1)
    try:

        while True:
            client_socket, addr = server.accept()
            print '[===>] Received incoming connection from %s:%d' % (addr[0], addr[1])
            proxy_thread = threading.Thread(target=proxy_handler, args=(client_socket, addr))
            proxy_thread.start()
    except KeyboardInterrupt:
        server.close()
        sys.exit(1)
    finally:
        print 'server close'
        server.close()


def main():
    if len(sys.argv[1:]) != 5:
        print 'usage'
        sys.exit(0)

    local_host = sys.argv[1]
    local_port = int(sys.argv[2])

    remote_host = sys.argv[3]
    remote_port = int(sys.argv[4])

    receive_first = sys.argv[5]

    if "True" in receive_first:
        receive_first = True
    else:
        receive_first = False

        # server_loop(local_host,local_port,remote_host,remote_port,receive_first)


if __name__ == '__main__':
    # main()
    server_loop(9997)

